package utils

import (
	"fmt"
	"sync/atomic"
	"time"
)

type WaitWithTimeout struct {
	cnt int32
}

func NewWaitWithTimeout() *WaitWithTimeout {
	rval := &WaitWithTimeout{}
	return rval
}

func NewWaitWithTimeoutAdd1() *WaitWithTimeout {
	rval := NewWaitWithTimeout()
	rval.Add(1)
	return rval
}

func (this *WaitWithTimeout) Add(delta int32) {
	atomic.AddInt32(&this.cnt, delta)
}

func (this *WaitWithTimeout) Done() {
	atomic.AddInt32(&this.cnt, -1)
}

func (this *WaitWithTimeout) WaitFor(timeout time.Duration) bool {
	t1 := time.Now()
	for {
		time.Sleep(time.Millisecond * 100)
		if this.cnt <= 0 {
			return true
		}
		if time.Since(t1) > timeout {
			return false
		}
	}
}

type WaitWithTimeoutEx struct {
	ch chan byte
}

func NewWaitWithTimeoutEx() *WaitWithTimeoutEx {
	rval := &WaitWithTimeoutEx{}
	rval.ch = make(chan byte, 4)
	return rval
}

func (this *WaitWithTimeoutEx) Done() {
	this.ch <- 1
}

func (this *WaitWithTimeoutEx) WaitFor(timeout time.Duration) bool {
	select {
	case <-time.After(timeout):
		return false
	case <-this.ch:
		return true
	}
}

type Timer struct {
	object_dna    uint32
	intervaltype  int // 0, interval, 1:fixed
	intervalDNA   int32
	interval      time.Duration
	SkipFirstTime int8
	Name          string
	Tag           interface{}
	OnTimer       func(tag interface{})
	TrigID        interface{}
	LastExecT     time.Time
}

func NewTimer() *Timer {
	return &Timer{
		object_dna:    NewObjectDNA(),
		SkipFirstTime: 1,
	}
}

func (this *Timer) GetInterval() time.Duration {
	return this.interval
}

/*
**

	配置间隔, 启动任务
	type:0, interval, 1:fixedInterval
*/
func (this *Timer) ConfigInterval(interval time.Duration, intervaltype int) bool {
	isChanged := false
	if interval <= 0 {
		this.Close()
		return true
	}
	if this.interval != interval {
		this.interval = interval
		isChanged = true
	}

	if this.intervaltype != intervaltype {
		this.intervaltype = intervaltype
		isChanged = true
	}

	if isChanged {
		this.intervalDNA++
		this.restartInterval()
	}
	return isChanged
}

func (this *Timer) Close() {
	this.intervalDNA++
}

func (this *Timer) TaskStatusInfo() string {
	return DefaultWorkers().GroupSimpleStatus(this.TrigID)
}

func (this *Timer) restartInterval() {
	dna := this.intervalDNA
	if this.TrigID == nil {
		this.TrigID = fmt.Sprintf("timer_%d", this.object_dna)
	}

	if this.intervaltype == 1 {
		AddTaskFxiedInterval(this.TrigID,
			this.interval, func() bool {
				if dna != this.intervalDNA {
					return false
				}
				if this.OnTimer != nil {
					this.OnTimer(this.Tag)
					this.LastExecT = time.Now()
				}
				return true
			})
	} else {
		var startTime = time.Now().Add(time.Second)
		if this.SkipFirstTime == 1 {
			startTime = time.Now().Add(this.interval)
		}
		AddTaskInterval(this.TrigID,
			func() bool {
				if dna != this.intervalDNA {
					return false
				}
				if this.OnTimer != nil {
					this.OnTimer(this.Tag)
					this.LastExecT = time.Now()
				}
				return true
			}, this.interval, startTime)
	}

}

func WaitTimeOut(d time.Duration, fn func()) bool {
	complete := make(chan byte)
	go func() {
		fn()
		complete <- 1
	}()
	timer := time.NewTimer(d)
	select {
	case <-complete:
		if !timer.Stop() {
			<-timer.C
		}
		return true
	case <-timer.C:
		return false
	}
}
